(function() {

  /**
   * Quadratic easing in
   * @method easeInQuad
   * @memberOf fabric.util.ease
   */
  function easeInQuad(t, b, c, d) {
    return c*(t/=d)*t + b;
  }

  /**
   * Quadratic easing out
   * @method easeOutQuad
   * @memberOf fabric.util.ease
   */
  function easeOutQuad(t, b, c, d) {
    return -c *(t/=d)*(t-2) + b;
  }

  /**
   * Quadratic easing in and out
   * @method easeInOutQuad
   * @memberOf fabric.util.ease
   */
  function easeInOutQuad(t, b, c, d) {
    t /= (d/2);
    if (t < 1) return c/2*t*t + b;
    return -c/2 * ((--t)*(t-2) - 1) + b;
  }

  /**
   * Cubic easing in
   * @method easeInCubic
   * @memberOf fabric.util.ease
   */
  function easeInCubic(t, b, c, d) {
    return c*(t/=d)*t*t + b;
  }

  /**
   * Cubic easing out
   * @method easeOutCubic
   * @memberOf fabric.util.ease
   */
  function easeOutCubic(t, b, c, d) {
    return c*((t=t/d-1)*t*t + 1) + b;
  }

  /**
   * Cubic easing in and out
   * @method easeInOutCubic
   * @memberOf fabric.util.ease
   */
  function easeInOutCubic(t, b, c, d) {
    t /= d/2;
    if (t < 1) return c/2*t*t*t + b;
    return c/2*((t-=2)*t*t + 2) + b;
  }

  /**
   * Quartic easing in
   * @method easeInQuart
   * @memberOf fabric.util.ease
   */
  function easeInQuart(t, b, c, d) {
    return c*(t/=d)*t*t*t + b;
  }

  /**
   * Quartic easing out
   * @method easeOutQuart
   * @memberOf fabric.util.ease
   */
  function easeOutQuart(t, b, c, d) {
    return -c * ((t=t/d-1)*t*t*t - 1) + b;
  }

  /**
   * Quartic easing in and out
   * @method easeInOutQuart
   * @memberOf fabric.util.ease
   */
  function easeInOutQuart(t, b, c, d) {
    t /= d/2;
    if (t < 1) return c/2*t*t*t*t + b;
    return -c/2 * ((t-=2)*t*t*t - 2) + b;
  }

  /**
   * Quintic easing in
   * @method easeInQuint
   * @memberOf fabric.util.ease
   */
  function easeInQuint(t, b, c, d) {
    return c*(t/=d)*t*t*t*t + b;
  }

  /**
   * Quintic easing out
   * @method easeOutQuint
   * @memberOf fabric.util.ease
   */
  function easeOutQuint(t, b, c, d) {
    return c*((t=t/d-1)*t*t*t*t + 1) + b;
  }

  /**
   * Quintic easing in and out
   * @method easeInOutQuint
   * @memberOf fabric.util.ease
   */
  function easeInOutQuint(t, b, c, d) {
    t /= d/2;
    if (t < 1) return c/2*t*t*t*t*t + b;
    return c/2*((t-=2)*t*t*t*t + 2) + b;
  }

  /**
   * Sinusoidal easing in
   * @method easeInSine
   * @memberOf fabric.util.ease
   */
  function easeInSine(t, b, c, d) {
    return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
  }

  /**
   * Sinusoidal easing out
   * @method easeOutSine
   * @memberOf fabric.util.ease
   */
  function easeOutSine(t, b, c, d) {
    return c * Math.sin(t/d * (Math.PI/2)) + b;
  }

  /**
   * Sinusoidal easing in and out
   * @method easeInOutSine
   * @memberOf fabric.util.ease
   */
  function easeInOutSine(t, b, c, d) {
    return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
  }

  /**
   * Exponential easing in
   * @method easeInExpo
   * @memberOf fabric.util.ease
   */
  function easeInExpo(t, b, c, d) {
    return (t===0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
  }

  /**
   * Exponential easing out
   * @method easeOutExpo
   * @memberOf fabric.util.ease
   */
  function easeOutExpo(t, b, c, d) {
    return (t===d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
  }

  /**
   * Exponential easing in and out
   * @method easeInOutExpo
   * @memberOf fabric.util.ease
   */
  function easeInOutExpo(t, b, c, d) {
    if (t===0) return b;
    if (t===d) return b+c;
    t /= d/2;
    if (t < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
    return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
  }

  /**
   * Circular easing in
   * @method easeInCirc
   * @memberOf fabric.util.ease
   */
  function easeInCirc(t, b, c, d) {
    return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
  }

  /**
   * Circular easing out
   * @method easeOutCirc
   * @memberOf fabric.util.ease
   */
  function easeOutCirc(t, b, c, d) {
    return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
  }

  /**
   * Circular easing in and out
   * @method easeInOutCirc
   * @memberOf fabric.util.ease
   */
  function easeInOutCirc(t, b, c, d) {
    t /= d/2;
    if (t < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
    return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
  }

  /**
   * Elastic easing in
   * @method easeInElastic
   * @memberOf fabric.util.ease
   */
  function easeInElastic(t, b, c, d) {
    var s=1.70158;var p=0;var a=c;
    if (t===0) return b;
    t /= d;
    if (t===1) return b+c;
    if (!p) p=d*0.3;
    if (a < Math.abs(c)) { a=c; s=p/4; }
    else s = p/(2*Math.PI) * Math.asin (c/a);
    return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
  }

  /**
   * Elastic easing out
   * @method easeOutElastic
   * @memberOf fabric.util.ease
   */
  function easeOutElastic(t, b, c, d) {
    var s=1.70158;var p=0;var a=c;
    if (t===0) return b;
    t /= d;
    if (t===1) return b+c;
    if (!p) p=d*0.3;
    if (a < Math.abs(c)) { a=c; s=p/4; }
    else s = p/(2*Math.PI) * Math.asin (c/a);
    return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
  }

  /**
   * Elastic easing in and out
   * @method easeInOutElastic
   * @memberOf fabric.util.ease
   */
  function easeInOutElastic(t, b, c, d) {
    var s=1.70158;var p=0;var a=c;
    if (t===0) return b;
    t /= d/2;
    if (t===2) return b+c;
    if (!p) p=d*(0.3*1.5);
    if (a < Math.abs(c)) { a=c; s=p/4; }
    else s = p/(2*Math.PI) * Math.asin (c/a);
    if (t < 1) return -0.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
    return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
  }

  /**
   * Backwards easing in
   * @method easeInBack
   * @memberOf fabric.util.ease
   */
  function easeInBack(t, b, c, d, s) {
    if (s === undefined) s = 1.70158;
    return c*(t/=d)*t*((s+1)*t - s) + b;
  }

  /**
   * Backwards easing out
   * @method easeOutBack
   * @memberOf fabric.util.ease
   */
  function easeOutBack(t, b, c, d, s) {
    if (s === undefined) s = 1.70158;
    return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
  }

  /**
   * Backwards easing in and out
   * @method easeInOutBack
   * @memberOf fabric.util.ease
   */
  function easeInOutBack(t, b, c, d, s) {
    if (s === undefined) s = 1.70158;
    t /= d/2;
    if (t < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
    return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
  }

  /**
   * Bouncing easing in
   * @method easeInBounce
   * @memberOf fabric.util.ease
   */
  function easeInBounce(t, b, c, d) {
    return c - easeOutBounce (d-t, 0, c, d) + b;
  }

  /**
   * Bouncing easing out
   * @method easeOutBounce
   * @memberOf fabric.util.ease
   */
  function easeOutBounce(t, b, c, d) {
    if ((t/=d) < (1/2.75)) {
      return c*(7.5625*t*t) + b;
    } else if (t < (2/2.75)) {
      return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
    } else if (t < (2.5/2.75)) {
      return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
    } else {
      return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
    }
  }

  /**
   * Bouncing easing in and out
   * @method easeInOutBounce
   * @memberOf fabric.util.ease
   */
  function easeInOutBounce(t, b, c, d) {
    if (t < d/2) return easeInBounce (t*2, 0, c, d) * 0.5 + b;
    return easeOutBounce (t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
  }

  /**
   * See <a href="http://gizma.com/easing/">Easing Equations by Robert Penner</a>
   * @namespace fabric.util.ease
   */
  fabric.util.ease = {
    easeInQuad: easeInQuad,
    easeOutQuad: easeOutQuad,
    easeInOutQuad: easeInOutQuad,
    easeInCubic: easeInCubic,
    easeOutCubic: easeOutCubic,
    easeInOutCubic: easeInOutCubic,
    easeInQuart: easeInQuart,
    easeOutQuart: easeOutQuart,
    easeInOutQuart: easeInOutQuart,
    easeInQuint: easeInQuint,
    easeOutQuint: easeOutQuint,
    easeInOutQuint: easeInOutQuint,
    easeInSine: easeInSine,
    easeOutSine: easeOutSine,
    easeInOutSine: easeInOutSine,
    easeInExpo: easeInExpo,
    easeOutExpo: easeOutExpo,
    easeInOutExpo: easeInOutExpo,
    easeInCirc: easeInCirc,
    easeOutCirc: easeOutCirc,
    easeInOutCirc: easeInOutCirc,
    easeInElastic: easeInElastic,
    easeOutElastic: easeOutElastic,
    easeInOutElastic: easeInOutElastic,
    easeInBack: easeInBack,
    easeOutBack: easeOutBack,
    easeInOutBack: easeInOutBack,
    easeInBounce: easeInBounce,
    easeOutBounce: easeOutBounce,
    easeInOutBounce: easeInOutBounce
  };

}());